package com.cmc.cloud.cmclink.doc.service.impl.so;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cmc.cloud.cmclink.doc.api.document.emums.*;
import com.cmc.cloud.cmclink.doc.dto.RestoreSpace;
import com.cmc.cloud.cmclink.doc.entity.*;
import com.cmc.cloud.cmclink.doc.mapper.SoMapper;
import com.cmc.cloud.cmclink.doc.mapper.SpecialCargoApplyMapper;
import com.cmc.cloud.cmclink.doc.service.approvespace.AutoSpaceService;
import com.cmc.cloud.cmclink.doc.service.so.SoAmendApplyService;
import com.cmc.cloud.cmclink.doc.service.so.SoCommonService;
import com.cmc.cloud.cmclink.doc.service.special.SpecialModifyVelVoyService;
import com.cmes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cmes.framework.security.core.util.SecurityFrameworkUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
 * @author chengzheng
 * @date 2025/08/14
 */
@Service
@Validated
public class SoCommonServiceImpl implements SoCommonService {
    @Resource
    private SoMapper soMapper;
    @Resource
    private SoVslvoyServiceImpl soVslvoyService;
    @Resource
    private SpecialCargoApplyMapper specialCargoApplyMapper;
    @Resource
    private SoCargoServiceImpl soCargoService;
    @Resource
    SoAmendApplyService soAmendApplyService;
    @Resource
    private SoServiceImpl soService;
    @Resource
    private SpecialModifyVelVoyService specialModifyVelVoyService;
    @Resource
    private AutoSpaceService autoSpaceService;


    private static String SO_REJECT = "SO REJECT";

    private static String SO_CANCEL = "SO CANCEL";

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void syncSoStatusSpecial(Long soId, String specialCargoApproveStatus) {
        //状态转换
        if (ApprovalStatusEnum.APPROVED.getValue().equals(specialCargoApproveStatus)) {
            syncSoStatus(soMapper.selectById(soId), ApproveStatusEnum.APPROVED.getValue(), false);
        }
        if (ApprovalStatusEnum.REJECT.getValue().equals(specialCargoApproveStatus)) {
            syncSoStatus(soMapper.selectById(soId), ApproveStatusEnum.REJECTED.getValue(), false);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void syncSoStatus(Long soId, String approveStatus) {
        syncSoStatus(soMapper.selectById(soId), approveStatus, true);
    }

    @Transactional(rollbackFor = Exception.class)
    public void syncSoStatus(Long soId, String approveStatus, boolean fromSo) {
        syncSoStatus(soMapper.selectById(soId), approveStatus, fromSo);
    }

    @Transactional(rollbackFor = Exception.class)
    public void syncSoStatus(SoDO so, String approveStatus, boolean fromSo) {
        if (so == null) {
            return;
        }
        // 当前更改的内容状态
        List<SoVslvoyDO> soVslvoyList = soVslvoyService.seleteBySoId(so.getId());
        //判断是否有特种货
        boolean hasSpecial = checkSoCargoIfHaveSpecial(so.getId());
        SpecialCargoApplyDO specialCargoApply = getSpecialCargoApplyBySoId(so.getId(), so.getBookingNo());
        if (ApproveStatusEnum.APPROVED.getValue().equals(approveStatus)) {
            long spacePassCount = soVslvoyList.stream().filter(s -> Objects.equals(ApproveStatusEnum.APPROVED.getValue(), s.getSpaceApproveStatus())).count();
            boolean vslvoyPass = soVslvoyList.size() == spacePassCount;
            //特种货审批状态
            boolean specialPass = checkSpecialCargoApplyStatus(specialCargoApply);
            boolean check = SoContentStatusEnum.APPROVED.getValue().equals(so.getSoContentStatus()) && vslvoyPass && (hasSpecial == false || specialPass == true);
            if (check) {
                so.setSoStatus(SoStatusEnum.BookingConfirmed.getValue());
                soMapper.updateById(so);
            }
        }
        if (ApproveStatusEnum.REJECTED.getValue().equals(approveStatus)) {
            //特种货审批直接拒绝
            if (specialCargoApply != null && fromSo == true) {
                specialCargoApply.setApplyStatus(ApplyStatusEnum.REJECT.getValue());
                specialCargoApply.setApplyRemark(SO_REJECT);
                specialCargoApply.setUpdateTime(LocalDateTime.now());
                specialCargoApply.setUpdater(String.valueOf(SecurityFrameworkUtils.getLoginUserId()));
                //正常都是按照ID更新，修改内容审批时，新SO的ID ，特种货还是旧的ID，通过booking关联的
                if(Objects.equals(so.getId(),specialCargoApply.getSoId())) {
                    specialCargoApplyMapper.updateById(specialCargoApply);
                }
            }
            so.setSoStatus(SoStatusEnum.BookingRejected.getValue());
            soMapper.updateById(so);
        }
        // 只有订舱取消
        if (SoStatusEnum.BookingCancelledByCustomer.getValue().equals(approveStatus)) {
            if (specialCargoApply != null && fromSo == true) {
                specialCargoApply.setApplyStatus(ApplyStatusEnum.APPLY_CANCELLED.getValue());
                specialCargoApply.setApplyRemark(SO_CANCEL);
                specialCargoApply.setUpdateTime(LocalDateTime.now());
                specialCargoApply.setUpdater(String.valueOf(SecurityFrameworkUtils.getLoginUserId()));
                if(Objects.equals(so.getId(),specialCargoApply.getSoId())) {
                    specialCargoApplyMapper.updateById(specialCargoApply);
                }
            }
        }
        syncAmendApply(so);
    }

    public void syncAmendApply(SoDO newSo) {
        SoAmendApplyDO applyLast = soAmendApplyService.getBySoId(newSo.getId(), Arrays.asList(ContentChangeStatusEnum.BOOKING_CHANGE_PROCESSING.getValue(), ContentChangeStatusEnum.BOOKING_CHANGE_AWAITING_MATERIAL_UPLOADED.getValue()));
        if (applyLast == null) {
            return;
        }

        if (SoStatusEnum.BookingConfirmed.getValue().equals(newSo.getSoStatus())) {
            if (Objects.equals(SoAmendOperateTypeEnum.AMEND_SO.getValue(), applyLast.getOperatianType())) {
                //内容审核通过，判断航线是否都已经审批
                List<SoVslvoyDO> vslvoyList = soVslvoyService.seleteBySoId(newSo.getId());
                List<Long> returnAllocationIdList = new ArrayList<>(8);
                List<Long> returnIdList = new ArrayList<>(8);
                vslvoyList.forEach(e -> {
                    //内容修改导致的航线重新审批
                    if (e.getReturnAllocationId() != null) {
                        returnAllocationIdList.add(e.getReturnAllocationId());
                        returnIdList.add(e.getId());
                    }
                });
                // 重置分配 旧自动批舱清理
                if (CollectionUtil.isNotEmpty(returnAllocationIdList)) {
                    soVslvoyService.setAllocationIdNull(returnIdList);
                    List<RestoreSpace> restoreSpaceList = new ArrayList<>(8);
                    restoreSpaceList.add(new RestoreSpace(newSo.getOldId(), returnAllocationIdList));
                    autoSpaceService.restoreAllocatedSpace(restoreSpaceList);
                }
                // 同步特种货
                exchangeSoIdInSpecial(newSo.getOldId(), newSo.getId());
            }
            if (Objects.equals(SoAmendOperateTypeEnum.CHANGE_VESSEL.getValue(), applyLast.getOperatianType())) {
                //航线修改 旧自动批舱清理
                List<SoVslvoyDO> vslvoyOldList = soVslvoyService.seleteBySoId(newSo.getOldId());
                List<SoVslvoyDO> vslvoyNewList = soVslvoyService.seleteBySoId(newSo.getId());
                //未更改的
                List<Long> noChangeAllocationIds = vslvoyNewList.stream().filter(e -> e.getAllocationId() != null).map(e -> e.getAllocationId()).collect(Collectors.toList());
                List<Long> returnAllocationIdList = new ArrayList<>(8);
                vslvoyOldList.forEach(e -> {
                    if (e.getAllocationId() != null) {
                        if (noChangeAllocationIds == null || noChangeAllocationIds.contains(e.getAllocationId()) == false) {
                            returnAllocationIdList.add(e.getAllocationId());
                        }
                    }
                });
                if (CollectionUtil.isNotEmpty(returnAllocationIdList)) {
                    List<RestoreSpace> restoreSpaceList = new ArrayList<>(8);
                    restoreSpaceList.add(new RestoreSpace(newSo.getOldId(), returnAllocationIdList));
                    autoSpaceService.restoreAllocatedSpace(restoreSpaceList);
                }
                specialModifyVelVoyService.updateSpecialApplyInfo(true, newSo.getOldId(), newSo.getId());
            }
            newSo.setValidStatus(ValidStatusEnum.DEFAULT_VALID.getValue());
            soService.updateById(newSo);

            SoDO oldSo = soService.getSo(newSo.getOldId());
            oldSo.setValidStatus(ValidStatusEnum.INVALID.getValue());
            soService.updateById(oldSo);

            //操作保存
            applyLast.setSoAmendStatus(ContentChangeStatusEnum.BOOKING_CHANGE_CONFIRMED.getValue());
            updateSoAmendApplyDO(applyLast);
        }
        if (SoStatusEnum.BookingRejected.getValue().equals(newSo.getSoStatus())) {
            newSo.setValidStatus(ValidStatusEnum.INVALID.getValue());
            soService.updateById(newSo);
            applyLast.setSoAmendStatus(ContentChangeStatusEnum.BOOKING_CHANGE_REJECTED.getValue());
            updateSoAmendApplyDO(applyLast);
            /*if (Objects.equals(SoAmendOperateTypeEnum.CHANGE_VESSEL.getValue(), applyLast.getOperatianType())) {
                specialModifyVelVoyService.updateSpecialApplyInfo(false, newSo.getOldId(), newSo.getId());
            }*/
        }
    }

    public void updateSoAmendApplyDO(SoAmendApplyDO applyLast) {
        applyLast.setApproveUser(String.valueOf(SecurityFrameworkUtils.getLoginUserId()));
        applyLast.setApproveTime(LocalDateTime.now());
        soAmendApplyService.updateById(applyLast);
    }

    public SoDO getSoByBookingNo(String bookingNo) {
        // 根据 订舱号 查找最近的一个审批
        LambdaQueryWrapperX<SoDO> queryWrapperX = new LambdaQueryWrapperX<SoDO>();
        queryWrapperX.eq(SoDO::getBookingNo, bookingNo);
        queryWrapperX.eq(SoDO::getValidStatus, ValidStatusEnum.DEFAULT_VALID.getValue());
        queryWrapperX.orderByDesc(SoDO::getId);
        queryWrapperX.last("LIMIT 1");
        return soMapper.selectOne(queryWrapperX);
    }

    public boolean checkSoCargoIfHaveSpecial(Long soId) {
        List<SoCargoDO> cargoList = soCargoService.seleteBySoId(soId);
        for (SoCargoDO e : cargoList) {
            if (SoCargoDO.checkSpecialCargo(e)) {
                return true;
            }
        }
        return false;
    }

    public void exchangeSoIdInSpecial(Long oldSoId, Long newSoId) {
        LambdaUpdateWrapper<SpecialCargoApplyDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(SpecialCargoApplyDO::getSoId, oldSoId);
        updateWrapper.set(SpecialCargoApplyDO::getSoId, newSoId);
        updateWrapper.set(SpecialCargoApplyDO::getUpdater, String.valueOf(SecurityFrameworkUtils.getLoginUserId()));
        updateWrapper.set(SpecialCargoApplyDO::getUpdateTime, LocalDateTime.now());
        specialCargoApplyMapper.update(null, updateWrapper);
    }

    public SpecialCargoApplyDO getSpecialCargoApplyBySoId(Long soId, String bookingNo) {
        SpecialCargoApplyDO specialCargoApply = null;
        // 根据 订舱号 查找最近的一个审批
        LambdaQueryWrapperX<SpecialCargoApplyDO> queryWrapperX = new LambdaQueryWrapperX<SpecialCargoApplyDO>();
        queryWrapperX.eq(SpecialCargoApplyDO::getSoId, soId);
        queryWrapperX.orderByDesc(SpecialCargoApplyDO::getId);
        queryWrapperX.last("LIMIT 1");
        specialCargoApply = specialCargoApplyMapper.selectOne(queryWrapperX);
        if (specialCargoApply != null) {
            return specialCargoApply;
        }
        // 根据 订舱号 查找最近的一个审批,新的修改申请会查询不到旧的审批
        LambdaQueryWrapperX<SpecialCargoApplyDO> queryWrapper = new LambdaQueryWrapperX<SpecialCargoApplyDO>();
        queryWrapper.eq(SpecialCargoApplyDO::getBookingNo, bookingNo);
        queryWrapper.orderByDesc(SpecialCargoApplyDO::getId);
        queryWrapper.last("LIMIT 1");
        return specialCargoApplyMapper.selectOne(queryWrapper);
    }

    public Map<Long, SpecialCargoApplyDO> getSpecialCargoApplyBySoIds(Collection<Long> soIds) {
        // 根据 订舱号 查找最近的一个审批
        LambdaQueryWrapperX<SpecialCargoApplyDO> queryWrapperX = new LambdaQueryWrapperX<SpecialCargoApplyDO>();
        queryWrapperX.in(SpecialCargoApplyDO::getSoId, soIds);
        queryWrapperX.orderByDesc(SpecialCargoApplyDO::getId);
        return specialCargoApplyMapper.selectList(queryWrapperX).stream().collect(Collectors.toMap(SpecialCargoApplyDO::getSoId, e -> e, (first, second) -> first));
    }

    public boolean checkSpecialCargoApplyStatus(SpecialCargoApplyDO specialCargoApply) {
        //没有特种货审批
        if (specialCargoApply == null) {
            return false;
        }
        if (ApplyStatusEnum.APPROVED.getValue().equals(specialCargoApply.getApplyStatus())) {
            return true;
        }
        return false;
    }

    public Map<String, SpecialCargoApplyDO> getSpecialCargoApplyByBookingNoMap(List<String> bookingNos) {
        Map<String, SpecialCargoApplyDO> mapResult = new HashMap<>(16);
        if (CollectionUtil.isEmpty(bookingNos)) {
            return mapResult;
        }
        // 根据 订舱号 查找最近的一个审批
        LambdaQueryWrapperX<SpecialCargoApplyDO> queryWrapperX = new LambdaQueryWrapperX<SpecialCargoApplyDO>();
        queryWrapperX.in(SpecialCargoApplyDO::getBookingNo, bookingNos);
        queryWrapperX.orderByAsc(SpecialCargoApplyDO::getId);
        return specialCargoApplyMapper.selectList(queryWrapperX).stream().filter(e -> StringUtils.isNotEmpty(e.getBookingNo())).collect(Collectors.toMap(SpecialCargoApplyDO::getBookingNo, Function.identity(), (oldKey, newKey) -> newKey));
    }

}
